// ## XX签名
// 抽象类是值 (类) 上下文，(最终编译成普通类)
// 抽象类不能被 实例化，但可以拥有构造函数 (可以构造：通过子类构造器的 `super()`, 或者 间接实例化 `new class extends AbstractModule { }()`  )
// 抽象类 可以继承抽象类，并实现一些方法，(这做到了 dynamic dispatch)
// 抽象类的 抽象成员不止是声明，并且在 子类中必须实现 (这一点与 declare 不同), 但是 declare 的成员类型也会被带到下一个子类

// 抽象类 可以有 抽象成员，也可以有 普通成员，抽象成员必须在 非抽象子类中实现
// 抽象类 (无抽象成员时) 在使用上可以理解为 protected 构造函数的类。但 抽象类不能在 自己的方法里实例化自己
// `abstract` 是ts 关键字

// 类可以构造一个对象，
// 抽象类能够构造一个 类

// 类的概念
// [override]: 一个继承类 的方法只取最近的 (定义或实现), 并且最近的定义或实现会默认覆盖父类的同名成员 (和普通类不一样)

// 抽象类更像类型类的概念，而不是类的概念
// finial class: 构造函数为私有的类，不能被继承
// 父子类之间 属性的继承是 逆变 (更具体)
// 父子类之间 方法的继承是 覆盖
// ts 类的构造器属性是 继承的

// 在创建类的时候也创建了同名的接口类型
abstract class ACls {
  // # 类的索引签名
  [k: string]: any;
  abstract n: number;

  protected constructor() {
    this.selfCheck();
  }
  selfCheck(): void {}

  abstract getN(): number;
}

abstract class ACls2 extends ACls {
  // `declare` 使类型收窄, 而 `declare abstract` 也是同样的效果
  declare n: 1 | 2 | 3;
  declare abstract nn: 4 | 5 | 6;
  // # 类的 重载签名
  // 作为限制 子类的成员的类型
  getN(): 1 | 2 | 3;
  getN(n: number): 4 | 5 | 6;
  getN(n?: number): number {
    return n ?? this.n;
  }
  // 覆盖 父抽象类的方法 需要 override
  abstract override selfCheck(): number;
}

class AClsImpl extends ACls2 {
  [k: string]: any;
  public constructor() {
    super();
  }
  override n: 1 | 2 | 3 = 1;
  declare nn: 4 | 5 | 6;
  newMethod(): never {
    throw new Error('Method not implemented.');
  }
  // 实现最近的 抽象方法
  selfCheck(): number {
    return 1;
  }
}
abstract class A {
  // 抽象类的构造器是 protected 的
  public constructor(a: number) {}
}
let B!: typeof A;
type _ = typeof B extends abstract new (...args: infer P) => any ? P : never;

const a: AClsImpl = new AClsImpl();

console.log(a.getN());

type Obj = {} & { new (): any } & { (): any }; // # 这部分就是 构造签名 // # 这部分是 调用签名

// 条件类型的赋值规则要求 在extend关键字后的类型和`检查器`所定义的类型相同
let x: <T>() => T extends number ? 1 : 2 = <T>() => 1 as never;
let y!: <Z>() => Z extends number ? 1 : 2;
y = x; // 你再寻思下会发生错误不

type Nv<T> = T extends never ? 1 : 2;
// ts 会 & 使用 可能 的 结果来判断 最终的值
let z!: Nv<never>;
//  ^?

declare const __nominal__type: unique symbol;

export interface Nominal<T, Identifier> {
  readonly [__nominal__type]: Identifier;
}
